﻿namespace EFS.Common.Serialization
{
	public class XmlWriter
	{
		#region Composition
		
		// document
		private System.Xml.Linq.XDocument xmlDoc = null;

		// writter
		private System.Xml.XmlWriter xmlWriter = null;
		
		#endregion

		#region Constructors

		/// <summary>
		/// Constructor
		/// </summary>
		public XmlWriter()
		{
			// create new document
			xmlDoc = new System.Xml.Linq.XDocument();

			// create writer
			xmlWriter = xmlDoc.CreateWriter();
		}

		#endregion

		#region Write

		/// <summary>
		/// Write array of items
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="startElement"></param>
		/// <param name="itemElement"></param>
		/// <param name="array"></param>
		public void Write<T>(System.String startElement, System.String itemElement, T[] array) where T : ISerializable
		{
			// check
			EFS.Common.Verify.String(startElement, "startElement");
			EFS.Common.Verify.String(itemElement, "itemElement");
			EFS.Common.Verify.Reference(array, "array");

			// create start
			xmlWriter.WriteStartElement(startElement);

			// serialize
			foreach (T t in array)
			{
				// create start
				xmlWriter.WriteStartElement(itemElement);

				// serialize
				t.Serialize(this);

				// create end
				xmlWriter.WriteEndElement();
			}

			// create end
			xmlWriter.WriteEndElement();
		}

		/// <summary>
		/// Write
		/// </summary>
		/// <param name="startElement"></param>
		/// <param name="s"></param>
		public void Write(System.String startElement, ISerializable s)
		{
			// check
			EFS.Common.Verify.String(startElement, "startElement");
			
			// create start
			xmlWriter.WriteStartElement(startElement);

			// serialize
			s.Serialize(this);

			// create end
			xmlWriter.WriteEndElement();
		}

		/// <summary>
		/// Write one object
		/// </summary>
		/// <param name="obj"></param>
		/// <param name="startElement"></param>
		public void WritePolymorphic(System.String startElement, ISerializable obj)
		{
			// check
			EFS.Common.Verify.String(startElement, "startElement");
			
			// create start
			xmlWriter.WriteStartElement(startElement);

			// check
			if (null != obj)
			{
				// write class
				xmlWriter.WriteAttributeString("Class", obj.GetType().AssemblyQualifiedName);

				// serialize
				obj.Serialize(this);
			}
			else
			{
				// write class
				xmlWriter.WriteAttributeString("IsNull", "true");
			}

			// create end
			xmlWriter.WriteEndElement();
		}

		/// Value
		public void WriteValue(
			System.String itemElement,
			EFS.Common.Values.Interfaces.Value value)
		{
			//check
			EFS.Common.Verify.String(itemElement, "itemElement");

			// start 
			xmlWriter.WriteStartElement(itemElement);

			// serialize
			value.Serialize(this);

			// end
			xmlWriter.WriteEndElement();
		}

		/// Char
		public void Write(
			System.String itemElement,
			System.Char? value)
		{
			EFS.Common.Verify.String(itemElement, "itemElement");
			xmlWriter.WriteElementString(itemElement, value.HasValue ? value.Value.ToString() : "");
		}

		/// String
		public void Write(
			System.String itemElement,
			System.String value)
		{
			EFS.Common.Verify.String(itemElement, "itemElement");
			xmlWriter.WriteElementString(itemElement, value);
		}

		/// Guid
		public void Write(
			System.String itemElement,
			System.Guid? value)
		{
			EFS.Common.Verify.String(itemElement, "itemElement");
			Write(itemElement, value.HasValue ? value.Value.ToString() : "");
		}

		/// DateTime
		public void Write(
			System.String itemElement,
			System.DateTime? value)
		{
			EFS.Common.Verify.String(itemElement, "itemElement");
			Write(itemElement, EFS.Common.Formats.ToString(value));
		}

		/// Int16
		public void Write(
			System.String itemElement,
			System.Int16? value)
		{
			EFS.Common.Verify.String(itemElement, "itemElement");
			Write(itemElement, value.HasValue ? value.Value.ToString() : "");
		}

		/// Int32
		public void Write(
			System.String itemElement,
			System.Int32? value)
		{
			EFS.Common.Verify.String(itemElement, "itemElement");
			Write(itemElement, value.HasValue ? value.Value.ToString() : "");
		}

		/// Int64
		public void Write(
			System.String itemElement,
			System.Int64? value)
		{
			EFS.Common.Verify.String(itemElement, "itemElement");
			Write(itemElement, value.HasValue ? value.Value.ToString() : "");
		}

		/// Boolean
		public void Write(
			System.String itemElement,
			System.Boolean? value)
		{
			EFS.Common.Verify.String(itemElement, "itemElement");
			Write(itemElement, value.HasValue ? value.Value.ToString() : "");
		}

		/// Double
		public void Write(
			System.String itemElement,
			System.Double? value)
		{
			EFS.Common.Verify.String(itemElement, "itemElement");
			Write(itemElement, value.HasValue ? value.Value.ToString() : "");
		}

		/// Decimal
		public void Write(
			System.String itemElement,
			System.Decimal? value)
		{
			EFS.Common.Verify.String(itemElement, "itemElement");
			Write(itemElement, value.HasValue ? value.Value.ToString() : "");
		}

		/// <summary>
		/// Write array of String
		/// </summary>
		/// <param name="startElement"></param>
		/// <param name="itemElement"></param>
		/// <param name="array"></param>
		public void Write(System.String startElement, System.String itemElement, System.String[] array)
		{
			// check
			EFS.Common.Verify.String(startElement, "startElement");
			EFS.Common.Verify.String(itemElement, "itemElement");

			// create start
			xmlWriter.WriteStartElement(startElement);

			// write all items
			if (null != array)
			{
				// serialize
				foreach (System.String s in array)
				{
					Write(itemElement, s);
				}
			}

			// create end
			xmlWriter.WriteEndElement();
		}

		#endregion

		#region Tools

		/// <summary>
		/// Get Xml tesxt
		/// </summary>
		public System.String Text
		{
			get { return xmlDoc.ToString(); }
		}

		/// <summary>
		/// Close
		/// </summary>
		public void Close()
		{
			xmlWriter.Close();
		}

		#endregion
	}
}
